package cn.zf233.xcloud.service.impl;

import cn.zf233.xcloud.commom.Const;
import cn.zf233.xcloud.commom.R;
import cn.zf233.xcloud.commom.enums.*;
import cn.zf233.xcloud.config.lockpool.IXCloudThreadPool;
import cn.zf233.xcloud.entity.File;
import cn.zf233.xcloud.entity.User;
import cn.zf233.xcloud.mapper.FileMapper;
import cn.zf233.xcloud.mapper.UserMapper;
import cn.zf233.xcloud.service.FileService;
import cn.zf233.xcloud.service.MessageService;
import cn.zf233.xcloud.service.UserService;
import cn.zf233.xcloud.util.CommonUtil;
import cn.zf233.xcloud.util.RedisUtil;
import cn.zf233.xcloud.util.ThreadSafeDateUtil;
import cn.zf233.xcloud.vo.UserVo;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrBuilder;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by zf233 on 2020/12/25
 * 用户服务
 */
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private FileMapper fileMapper;

    @Resource
    private FileService fileService;

    @Resource
    private MessageService messageService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private IXCloudThreadPool<Lock> lockPool;

    @Override
    public R<UserVo> login(User user) {
        R<UserVo> rPhone = checkUserInfo(user, null, new UserFieldENUM[]{UserFieldENUM.PHONE, UserFieldENUM.PASSWORD}, false);
        R<UserVo> rEmail = checkUserInfo(user, null, new UserFieldENUM[]{UserFieldENUM.EMAIL, UserFieldENUM.PASSWORD}, false);
        if (!rPhone.isSuccess() && !rEmail.isSuccess()) {
            return R.createByErrorMessage("登陆失败，格式有误或缺少参数");
        }
        User userInfo;
        if (rPhone.isSuccess()) {
            userInfo = userMapper.selectUserByPhone(user.getPhone());
        } else {
            userInfo = userMapper.selectUserByEmail(user.getEmail());
        }
        if (userInfo == null) {
            return R.createByErrorMessage("登陆失败");
        }
        if (UserStatusENUM.LOCK_USER.getCode().equals(userInfo.getStatus())) {
            return R.createByErrorMessage("您的账户已被锁定，待解锁后重试");
        }
        if (!user.getPassword().equals(userInfo.getPassword())) {
            return R.createByErrorMessage("登陆失败");
        }
        userLoginSuccessRecord(userInfo.getId());
        return R.createBySuccess("登陆成功", CommonUtil.assembleUserVoDetail(userInfo));
    }

    @Override
    public R<UserVo> loginQq(User user) {
        User userInfo = userMapper.selectUserByOpenId(user.getOpenId());
        if (userInfo == null) {
            String headUrl = null;
            if (StringUtils.isNotBlank(user.getHeadUrl()) && !user.getHeadUrl().contains("https") && user.getHeadUrl().contains("http")) {
                headUrl = user.getHeadUrl().replace("http", "https");
            }
            assembleRegisterUser(user, "QQ用户", UserSourceENUM.QQ_USER, UserStatusENUM.NORMAL_USER, headUrl);
            int result = userMapper.insert(user);
            if (result <= 0) {
                return R.createByErrorMessage("注册失败");
            }
            File file = assembleRootNodeOfRegistUser(user);
            result = fileMapper.insert(file);
            if (result <= 0) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return R.createByErrorMessage("登陆失败");
            }
            userLoginSuccessRecord(user.getId());
            return R.createBySuccess("登陆成功", CommonUtil.assembleUserVoDetail(user));
        }
        if (UserStatusENUM.LOCK_USER.getCode().equals(userInfo.getSource())) {
            return R.createByErrorMessage("您的账户已被锁定，待解锁后重试");
        }
        userLoginSuccessRecord(userInfo.getId());
        return R.createBySuccess("登陆成功", CommonUtil.assembleUserVoDetail(userInfo));
    }

    @Override
    public R<UserVo> codeLoginEmail(User user, String code) {
        R<UserVo> rCheck = checkUserInfo(user, code, new UserFieldENUM[]{UserFieldENUM.EMAIL}, true);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        User userInfo = userMapper.selectUserByEmail(user.getEmail());
        if (userInfo == null) {
            return R.createByErrorIllegalArgument("用户不存在");
        }
        if (UserStatusENUM.LOCK_USER.getCode().equals(userInfo.getStatus())) {
            return R.createByErrorMessage("您的账户已被锁定，待解锁后重试");
        }
        String key = Const.USER_LOGIN_CODE_EMAIL_PREFIX + userInfo.getId();
        if (!redisUtil.exists(key)) {
            return R.createByErrorMessage("无效的验证码");
        }
        if (redisUtil.ttl(key) < 1) {
            return R.createByErrorMessage("验证码已过期");
        }
        String vCode = redisUtil.get(key);
        if (code.equals(vCode)) {
            if (UserStatusENUM.EMAIL_UNVERIFIED.getCode().equals(userInfo.getStatus())) {
                userInfo.setStatus(UserStatusENUM.NORMAL_USER.getCode());
                int i = userMapper.updateByPrimaryKeySelective(userInfo);
                if (i <= 0) {
                    return R.createByErrorMessage("登陆失败");
                }
            }
            redisUtil.remove(key);
            userLoginSuccessRecord(userInfo.getId());
            return R.createBySuccess("登陆成功", CommonUtil.assembleUserVoDetail(userInfo));
        }
        return R.createByErrorMessage("验证码有误");
    }

    @Override
    public R<UserVo> codeLoginSms(User user, String code) {
        R<UserVo> rCheck = checkUserInfo(user, code, new UserFieldENUM[]{UserFieldENUM.PHONE}, true);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        User userInfo = userMapper.selectUserByPhone(user.getPhone());
        if (userInfo == null) {
            return R.createByErrorIllegalArgument("用户不存在");
        }
        if (UserStatusENUM.LOCK_USER.getCode().equals(userInfo.getSource())) {
            return R.createByErrorMessage("您的账户已被锁定，待解锁后重试");
        }
        String key = Const.USER_LOGIN_CODE_PHONE_PREFIX + userInfo.getId();
        if (!redisUtil.exists(key)) {
            return R.createByErrorMessage("无效的验证码");
        }
        if (redisUtil.ttl(key) <= 0) {
            return R.createByErrorMessage("验证码已过期");
        }
        String vCode = redisUtil.get(key);
        if (code.equals(vCode)) {
            if (UserStatusENUM.PHONE_UNVERIFIED.getCode().equals(userInfo.getStatus())) {
                userInfo.setStatus(UserStatusENUM.NORMAL_USER.getCode());
                int r = userMapper.updateByPrimaryKeySelective(userInfo);
                if (r <= 0) {
                    return R.createByErrorMessage("登陆失败");
                }
            }
            redisUtil.remove(key);
            userLoginSuccessRecord(userInfo.getId());
            return R.createBySuccess("登陆成功", CommonUtil.assembleUserVoDetail(userInfo));
        }
        return R.createByErrorMessage("验证码有误");
    }

    @Override
    public R getLoginCodeEmail(User user) {
        R<UserVo> rCheck = checkUserInfo(user, null, new UserFieldENUM[]{UserFieldENUM.EMAIL}, false);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        User userInfo = userMapper.selectUserByEmail(user.getEmail());
        if (userInfo == null) {
            assembleRegisterUser(user, user.getEmail(), UserSourceENUM.EMAIL_USER, UserStatusENUM.EMAIL_UNVERIFIED, null);
            int r = userMapper.insert(user);
            if (r > 0) {
                File rootNode = assembleRootNodeOfRegistUser(user);
                r = fileMapper.insert(rootNode);
                if (r > 0) {
                    userInfo = user;
                } else {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return R.createByErrorMessage("发送失败，请重试");
                }
            } else {
                return R.createByErrorMessage("发送失败，请重试");
            }
        }
        if (UserStatusENUM.LOCK_USER.getCode().equals(userInfo.getStatus())) {
            return R.createByErrorMessage("您的账户已被锁定，待解锁后重试");
        }
        String key = Const.USER_LOGIN_CODE_EMAIL_PREFIX + userInfo.getId();
        if (redisUtil.exists(key) && redisUtil.ttl(key) > 1) {
            return R.createBySuccess(redisUtil.ttl(key) + "秒后重新发送", redisUtil.ttl(key));
        }
        String code = CommonUtil.vCode();
        redisUtil.remove(key);
        redisUtil.set(key, code, 180L);
        R response = messageService.sendEmail(userInfo,
                "XCloud 验证码登陆",
                new StrBuilder("您的XCloud登陆验证码为 ")
                        .append(code)
                        .append(" 有效期180秒，请尽快登陆。")
                        .toString(),
                null,
                false);
        if (!response.isSuccess()) {
            return response;
        }
        return R.createBySuccess("验证码已成功发送，请注意查收", 180L);
    }

    @Override
    public R getLoginCodeSms(User user) {
        R<UserVo> rCheck = checkUserInfo(user, null, new UserFieldENUM[]{UserFieldENUM.PHONE}, false);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        User userInfo = userMapper.selectUserByPhone(user.getPhone());
        if (userInfo == null) {
            assembleRegisterUser(user, user.getPhone(), UserSourceENUM.PHONE_USER, UserStatusENUM.PHONE_UNVERIFIED, null);
            int r = userMapper.insert(user);
            if (r > 0) {
                File rootNode = assembleRootNodeOfRegistUser(user);
                r = fileMapper.insert(rootNode);
                if (r > 0) {
                    userInfo = user;
                } else {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    return R.createByErrorMessage("发送失败，请重试");
                }
            } else {
                return R.createByErrorMessage("发送失败，请重试");
            }
        }
        if (UserStatusENUM.LOCK_USER.getCode().equals(userInfo.getStatus())) {
            return R.createByErrorMessage("您的账户已被锁定，待解锁后重试");
        }
        String key = Const.USER_LOGIN_CODE_PHONE_PREFIX + userInfo.getId();
        if (redisUtil.exists(key) && redisUtil.ttl(key) > 1) {
            return R.createBySuccess(redisUtil.ttl(key) + "秒后重新发送", redisUtil.ttl(key));
        }
        String code = CommonUtil.vCode();
        R response = messageService.sendSMS(userInfo.getPhone(), code);
        redisUtil.remove(key);
        redisUtil.set(key, code, 180L);
        if (!response.isSuccess()) {
            return response;
        }
        return R.createBySuccess("验证码已成功发送，请注意查收", 180L);
    }

    @Override
    public R applyForLogout(User user) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorIllegalArgument("登陆失效，请重新登录");
        }
        userInfo.setStatus(UserStatusENUM.PHONE_LOGOUT.getCode());
        int r = userMapper.updateByPrimaryKeySelective(userInfo);
        if (r > 0) {
            return R.createBySuccessMessage("申请成功，等待审核");
        }
        return R.createByErrorMessage("申请失败");
    }

    @Override
    public R<UserVo> updateHeadUrl(User user, String url) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorIllegalArgument("登陆失效，请重新登录");
        }
        userInfo.setHeadUrl(url);
        int result = userMapper.updateByPrimaryKeySelective(userInfo);
        if (result > 0) {
            return R.createBySuccess("头像更新成功", CommonUtil.assembleUserVoDetail(userInfo));
        }
        return R.createByErrorMessage("头像更新失败");
    }

    @Override
    public R<UserVo> updatePassword(User user, String oldPassword) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorMessage("登陆失效，请重新登录");
        }
        R<UserVo> rCheck = checkUserInfo(user, null, new UserFieldENUM[]{UserFieldENUM.PASSWORD}, false);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        userInfo.setPassword(user.getPassword());
        int result = userMapper.updateByPrimaryKeySelective(userInfo);
        if (result > 0) {
            return R.createBySuccess("修改成功", CommonUtil.assembleUserVoDetail(userInfo));
        }
        return R.createByErrorMessage("修改失败");
    }

    @Override
    public R<UserVo> updateNickname(User user) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorMessage("登陆失效，请重新登录");
        }
        if (StringUtils.isNotBlank(userInfo.getNickname())
                && StringUtils.isNotBlank(user.getNickname())
                && userInfo.getNickname().equals(user.getNickname())) {
            return R.createByErrorMessage("未做任何修改");
        }
        R<UserVo> rCheck = checkUserInfo(user, null, new UserFieldENUM[]{UserFieldENUM.NICKNAME}, false);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        userInfo.setNickname(user.getNickname());
        int result = userMapper.updateByPrimaryKeySelective(userInfo);
        if (result > 0) {
            return R.createBySuccess("修改成功", CommonUtil.assembleUserVoDetail(userInfo));
        }
        return R.createByErrorMessage("修改失败");
    }

    @Override
    public R rebindPhone(User user) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorMessage("登陆失效，请重新登录");
        }
        R<UserVo> rCheck = checkUserInfo(user, null, new UserFieldENUM[]{UserFieldENUM.PHONE}, false);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        if (user.getPhone().equals(userInfo.getPhone())) {
            return R.createByErrorMessage("请勿重复绑定");
        }
        User exists = userMapper.selectUserByPhone(user.getPhone());
        if (exists != null) {
            return R.createByErrorMessage("手机已被占用");
        }
        String code = CommonUtil.vCode();
        String key = Const.USER_REBINDING_PHONE_PREFIX + user.getId();
        if (redisUtil.exists(key) && redisUtil.ttl(key) > 1) {
            return R.createByErrorMessage("上次绑定未成功，请于" + redisUtil.ttl(key) + "秒后重试");
        }
        String value = user.getPhone() + "#" + code;
        redisUtil.set(key, value, 180L);
        R rMsg = messageService.sendSMS(user.getPhone(), code);
        if (rMsg.isSuccess()) {
            return R.createBySuccess("验证码已成功发送，请注意查收", CommonUtil.assembleUserVoDetail(userInfo));
        }
        return rMsg;
    }

    @Override
    public R rebindEmail(User user) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorMessage("登陆失效，请重新登录");
        }
        R<UserVo> rCheck = checkUserInfo(user, null, new UserFieldENUM[]{UserFieldENUM.EMAIL}, false);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        if (user.getEmail().equals(userInfo.getEmail())) {
            return R.createByErrorMessage("请勿重复绑定");
        }
        User exists = userMapper.selectUserByEmail(user.getEmail());
        if (exists != null) {
            return R.createByErrorMessage("邮箱已被占用");
        }
        String code = CommonUtil.vCode();
        String key = Const.USER_REBINDING_EMAIL_PREFIX + user.getId();
        if (redisUtil.exists(key) && redisUtil.ttl(key) > 1) {
            return R.createByErrorMessage("上次绑定未成功，请于" + redisUtil.ttl(key) + "秒后重试");
        }
        String value = user.getEmail() + "#" + code;
        redisUtil.set(key, value, 180L);
        R rMsg = messageService.sendEmail(user,
                "XCloud 邮箱绑定",
                new StrBuilder("您的XCloud邮箱绑定验证码为 ")
                        .append(code)
                        .append(" 有效期180秒，请尽快进行绑定操作。")
                        .toString(),
                null,
                false);
        if (rMsg.isSuccess()) {
            return R.createBySuccess("验证码已成功发送，请注意查收", CommonUtil.assembleUserVoDetail(userInfo));
        }
        return rMsg;
    }

    @Override
    public R<UserVo> rebindCheckPhone(User user, String code) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorMessage("登陆失效，请重新登录");
        }
        R<UserVo> rCheck = checkUserInfo(user, code, new UserFieldENUM[]{UserFieldENUM.PHONE}, true);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        String key = Const.USER_REBINDING_PHONE_PREFIX + user.getId();
        if (!redisUtil.exists(key)) {
            return R.createByErrorMessage("绑定失败");
        }
        if (redisUtil.ttl(key) < 1) {
            return R.createByErrorMessage("验证码已超时");
        }
        String value = redisUtil.get(key);
        redisUtil.remove(key);
        if (StringUtils.isBlank(value)) {
            return R.createByErrorMessage("验证码已超时");
        }
        String[] split = value.split("#");
        String phone = split[0];
        String vCode = split[1];
        if (user.getPhone().equals(phone) && code.equals(vCode)) {
            userInfo.setPhone(user.getPhone());
            int r = userMapper.updateByPrimaryKeySelective(userInfo);
            if (r > 0) {
                return R.createBySuccess("绑定成功", CommonUtil.assembleUserVoDetail(userInfo));
            }
            return R.createBySuccessMessage("绑定失败");
        }
        return R.createByErrorMessage("目标手机不正确或验证码有误");
    }

    @Override
    public R<UserVo> rebindCheckEmail(User user, String code) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorMessage("登陆失效，请重新登录");
        }
        R<UserVo> rCheck = checkUserInfo(user, code, new UserFieldENUM[]{UserFieldENUM.EMAIL}, true);
        if (!rCheck.isSuccess()) {
            return rCheck;
        }
        String key = Const.USER_REBINDING_EMAIL_PREFIX + user.getId();
        if (!redisUtil.exists(key)) {
            return R.createByErrorMessage("绑定失败");
        }
        if (redisUtil.ttl(key) < 1) {
            return R.createByErrorMessage("验证码已超时");
        }
        String value = redisUtil.get(key);
        redisUtil.remove(key);
        if (StringUtils.isBlank(value)) {
            return R.createByErrorMessage("验证码已超时");
        }
        String[] split = value.split("#");
        String email = split[0];
        String vCode = split[1];
        if (user.getEmail().equals(email) && code.equals(vCode)) {
            userInfo.setEmail(user.getEmail());
            int r = userMapper.updateByPrimaryKeySelective(userInfo);
            if (r > 0) {
                return R.createBySuccess("绑定成功", CommonUtil.assembleUserVoDetail(userInfo));
            }
            return R.createBySuccessMessage("绑定失败");
        }
        return R.createByErrorMessage("目标邮箱不正确或验证码有误");
    }

    // 获取用户展示对象
    @Override
    public R<UserVo> getUserVoByPrimaryKey(Long userId) {
        User userInfo = userMapper.selectByPrimaryKey(userId);
        if (userInfo == null) {
            return R.createByErrorMessage("查无此人");
        }
        return R.createBySuccess("获取成功", CommonUtil.assembleUserVoDetail(userInfo));
    }

    @Override
    public R<UserVo> getUserVoByUid(Long uid) {
        User userInfo = userMapper.selectByUid(uid);
        if (userInfo == null) {
            return R.createByErrorMessage("查无此人");
        }
        return R.createBySuccess("获取成功", CommonUtil.assembleUserVoDetail(userInfo));
    }

    @Override
    public void userLoginSuccessRecord(Long userId) {
        redisUtil.bitSet(Const.USER_LOGIN_FLAG_BIT_SET_KEY, userId, true);
    }

    // 刷新用户等级
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R refreshUserLevelTask() {
        List<User> userList = userMapper.selectUsers();
        for (User user : userList) {

            // 判断登陆标志以增加用户成长值并计算新的等级
            if (redisUtil.bitGet(Const.USER_LOGIN_FLAG_BIT_SET_KEY, user.getId())) {
                user.setGrowthValue(user.getGrowthValue() + 1);
            }
            int level = (user.getGrowthValue() - 1) / 100 + 1;
            user.setLevel(level);

            // 依据用户等级刷新容量、流量、分享量等信息
            long levelFlow = level * Const.USER_BASE_TRAFFIC;
            long flow = levelFlow + (user.getDownloadFlow() >= levelFlow ? levelFlow : user.getDownloadFlow());
            user.setDownloadFlow(flow);
            user.setCapacity(level * Const.USER_BASE_CAPACITY);
            user.setShareNumber(level * Const.USER_BASE_SHARE_NUMBER);

            // 每日进行用户容量统计校准
            Long fileTotalSize = fileMapper.selectTotalFileSizeByUserId(user.getId());
            user.setUseCapacity(fileTotalSize);
            int result = userMapper.updateByPrimaryKeySelective(user);
            if (result <= 0) { // 重试
                userMapper.updateByPrimaryKeySelective(user);
            }
        }
        return R.createBySuccessMessage(userList.size() + " 个用户的容量校准和等级刷新操作已完成");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAndAlertUnauthenticatedUsers(boolean remove, boolean sendMsg) {
        List<User> userList = userMapper.selectUsers();
        long now = ThreadSafeDateUtil.now();
        for (User user : userList) {
            if (UserStatusENUM.NORMAL_USER.getCode().equals(user.getStatus())) {
                continue;
            }
            UserStatusENUM status = UserStatusENUM.exists(user.getStatus());
            if (status == null) {
                continue;
            }
            switch (status) {
                case PHONE_UNVERIFIED:
                case EMAIL_UNVERIFIED:
                    if (StringUtils.isBlank(user.getEmail()) && sendMsg) {
                        // 发送邮箱未验证提醒邮件
                        long days = (now - user.getCreateTime()) / TimeUnit.DAYS.toMillis(1L);
                        if (days % 3 == 0) {
                            messageService.sendEmail(user,
                                    "XCloud 用户提醒",
                                    "您的XCloud账号仍未进行邮箱验证，请及时验证。验证方式：获取邮箱登陆验证码后进行XCloud登陆即可。XCloud致力于保护您的隐私，您的满意是我们前进的动力。",
                                    null,
                                    false);
                        }
                    }
                    break;
                default:
                    break;
            }
            if (remove) {
                File file = fileMapper.selectRootNodeOfUserByPrimaryKey(user.getId());
                if (file != null) {
                    int resultUser = userMapper.deleteByPrimaryKey(user.getId());
                    int resultFile = fileMapper.deleteByPrimaryKey(file.getId());
                    if (resultUser <= 0 || resultFile <= 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }
                }
            }
        }
    }

    @Override
    public R agree(User user, Integer agree) {
        if (!(agree != null && (agree.equals(1) || agree.equals(0)))) {
            return R.createByErrorIllegalArgument("参数有误");
        }
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorIllegalArgument("登陆失效，请重新登陆");
        }
        if (userInfo.getAcceptAgree() == 1 && agree == 0) {
            return R.createByErrorMessage("已接受协议，如需注销请申请");
        }
        if (userInfo.getAcceptAgree() == 1 && agree == 1) {
            return R.createBySuccessMessage("接受协议成功");
        }
        if (agree.equals(1)) {
            userInfo.setAcceptAgree(1);
            int result = userMapper.updateByPrimaryKeySelective(userInfo);
            if (result > 0) {
                return R.createBySuccess("接受协议成功", CommonUtil.assembleUserVoDetail(userInfo));
            }
            return R.createByErrorMessage("服务器繁忙，请稍后再试");
        }
        Lock lock = lockPool.getCapacityLock(userInfo.getId());
        lock.lock();
        try {
            return ((UserServiceImpl) AopContext.currentProxy()).logout(userInfo);
        } finally {
            lockPool.unLock(lock);
        }
    }

    @Override
    public R chart(User user) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorIllegalArgument("登陆失效，请重新登陆");
        }
        Long id = user.getId();
        double unknownFileSizeTotal = DataUnitENUM
                .BYTE
                .decimalConvertUnit(fileMapper.classChart(id, ClassifyENUM.UNKNOWN.getCode()), DataUnitENUM.MB);
        double txtFileSizeTotal = DataUnitENUM
                .BYTE
                .decimalConvertUnit(fileMapper.classChart(id, ClassifyENUM.TXT.getCode()), DataUnitENUM.MB);
        double photoFileSizeTotal = DataUnitENUM
                .BYTE
                .decimalConvertUnit(fileMapper.classChart(id, ClassifyENUM.PHOTO.getCode()), DataUnitENUM.MB);
        double videoFileSizeTotal = DataUnitENUM
                .BYTE
                .decimalConvertUnit(fileMapper.classChart(id, ClassifyENUM.VIDEO.getCode()), DataUnitENUM.MB);
        double musicFileSizeTotal = DataUnitENUM
                .BYTE
                .decimalConvertUnit(fileMapper.classChart(id, ClassifyENUM.MUSIC.getCode()), DataUnitENUM.MB);
        double recycleFileSizeTotal = DataUnitENUM
                .BYTE
                .decimalConvertUnit(fileMapper.recycleSize(id), DataUnitENUM.MB);
        double free = DataUnitENUM
                .BYTE
                .decimalConvertUnit(userInfo.getCapacity() - userInfo.getUseCapacity(), DataUnitENUM.MB);
        Map<String, Object> map = new HashMap<>(8);
        map.put(ClassifyENUM.UNKNOWN.getDescribe(), unknownFileSizeTotal);
        map.put(ClassifyENUM.TXT.getDescribe(), txtFileSizeTotal);
        map.put(ClassifyENUM.PHOTO.getDescribe(), photoFileSizeTotal);
        map.put(ClassifyENUM.VIDEO.getDescribe(), videoFileSizeTotal);
        map.put(ClassifyENUM.MUSIC.getDescribe(), musicFileSizeTotal);
        map.put("recycle", recycleFileSizeTotal);
        map.put("free", free);
        return R.createBySuccess("您的XCloud网盘用量分布获取成功", map);
    }

    @Transactional(rollbackFor = Exception.class)
    public R logout(User user) {
        User userInfo = userMapper.selectByPrimaryKey(user.getId());
        if (userInfo == null) {
            return R.createByErrorIllegalArgument("登陆失效，等重新登陆");
        }
        File rootNode = fileMapper.selectRootNodeOfUserByPrimaryKey(userInfo.getId());
        R response = fileService.remove(new Long[]{rootNode.getId()}, userInfo);
        if (response.isSuccess()) {
            int result = userMapper.deleteByPrimaryKey(userInfo.getId());
            if (result <= 0) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return R.createBySuccessMessage("拒绝接受协议，注销失败，请重试");
            }
            String[] keys = new String[]{
                    Const.USER_LOGIN_CODE_PHONE_PREFIX + userInfo.getId().toString(),
                    Const.USER_LOGIN_CODE_EMAIL_PREFIX + userInfo.getId().toString()
            };
            for (String key : keys) {
                if (redisUtil.exists(key)) {
                    redisUtil.remove(key);
                }
            }
            return R.createBySuccessMessage("拒绝接受协议，注销成功");
        }
        return response;
    }

    // 组装用户注册对象
    private void assembleRegisterUser(User user, String nickname, UserSourceENUM sourceENUM,
                                      UserStatusENUM statusENUM, String headUrl) {
        user.setNickname(nickname);
        user.setHeadUrl(StringUtils.isBlank(headUrl) ? Const.DEFAULT_USER_HEAD_URL : headUrl);
        user.setAcceptAgree(0);
        user.setUid(CommonUtil.SnowFlakeUtil.generateId());
        user.setSource(sourceENUM.getCode());
        user.setStatus(statusENUM.getCode());
        user.setRole(UserRoleENUM.USER.getCode());
        user.setDownloadFlow(Const.USER_BASE_TRAFFIC);
        user.setShareNumber(Const.USER_BASE_SHARE_NUMBER);
        user.setCapacity(Const.USER_BASE_CAPACITY);
        user.setUseCapacity(0L);
        user.setLevel(1);
        user.setGrowthValue(0);
    }

    // 组装用户注册根路径对象
    private File assembleRootNodeOfRegistUser(User userInfo) {
        File rootNode = new File();
        rootNode.setUserId(userInfo.getId());
        rootNode.setShareId(-1L);
        rootNode.setParentId(-1L);
        rootNode.setFolder(1);
        rootNode.setDeleteFlag(0);
        return rootNode;
    }

    private R<UserVo> checkUserInfo(User userInfo, String code, UserFieldENUM[] needCheckFields, boolean checkCode) {
        if (userInfo == null) {
            return R.createByErrorIllegalArgument("目标参数有误");
        }
        if (checkCode) { // 避免枚举产生歧义，因此验证码直接进行格式验证即可
            if (StringUtils.isNotBlank(code)) {
                final String regex = "^\\d{6}$";
                Pattern pattern = Pattern.compile(regex);
                Matcher matcher = pattern.matcher(code);
                if (!matcher.find()) {
                    return R.createByErrorIllegalArgument("验证码格式有误");
                }
            } else {
                return R.createByErrorIllegalArgument("验证码不可为空");
            }
        }
        R<UserVo> serverResponse = R.createBySuccessMessage("指定字段验证成功");
        if (needCheckFields == null || needCheckFields.length == 0) {
            return serverResponse;
        }
        for (UserFieldENUM fieldENUM : needCheckFields) {
            switch (fieldENUM) {
                case NICKNAME:
                    if (StringUtils.isBlank(userInfo.getNickname())) {
                        serverResponse = R.createByErrorIllegalArgument("昵称不可为空");
                    }
                    if (userInfo.getNickname().length() < 3 || userInfo.getNickname().length() > 16) {
                        serverResponse = R.createByErrorIllegalArgument("昵称格式有误");
                    }
                    break;
                case PASSWORD:
                    if (StringUtils.isBlank(userInfo.getPassword())) {
                        serverResponse = R.createByErrorIllegalArgument("密码不可为空");
                    }
                    if (userInfo.getPassword().trim().length() != 32) {
                        serverResponse = R.createByErrorIllegalArgument("密码格式有误");
                    }
                    break;
                case EMAIL:
                    if (StringUtils.isNotBlank(userInfo.getEmail())) {
                        Pattern regex = Pattern.compile("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$");
                        Matcher matcher = regex.matcher(userInfo.getEmail());
                        if (!matcher.matches()) {
                            serverResponse = R.createByErrorIllegalArgument("邮箱格式有误");
                        }
                    } else {
                        serverResponse = R.createByErrorIllegalArgument("邮箱不可为空");
                    }
                    break;
                case PHONE:
                    if (StringUtils.isNotBlank(userInfo.getPhone())) {
                        final String regex = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$";
                        Pattern pattern = Pattern.compile(regex);
                        Matcher matcher = pattern.matcher(userInfo.getPhone());
                        if (!matcher.find()) {
                            serverResponse = R.createByErrorIllegalArgument("手机格式有误");
                        }
                    } else {
                        serverResponse = R.createByErrorIllegalArgument("手机不可为空");
                    }
                    break;
                default:
                    serverResponse = R.createByErrorIllegalArgument("目标参数有误");
                    break;
            }
            if (!serverResponse.isSuccess()) {
                break;
            }
        }
        return serverResponse;
    }
}